﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		PublicControllerBase.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;
using Dexter.DataTransferObject;
using Dexter.Domain.Model;
using Dexter.Logger.Contracts;
using Dexter.PluginManager;
using Dexter.Search;
using Dexter.Services;
using Dexter.Web.Mvc.ViewModel.ViewsData;
using Dexter.Web.Mvc.ViewsData;
using Dexter.Web.Utils;

namespace Dexter.Web.Mvc.Controllers {
	[PluginFilter]
	public class PublicControllerBase : DexterControllerBase {
		static readonly Regex searchPattern = new Regex ( "[?&]q=([^&#]+)" , RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant );
		static readonly string[] emptyStringArray = new string[0];
		readonly IBlogRollService blogRollService;
		readonly ICategoryService categoryService;
		readonly ICommentService commentService;
		readonly IPostService postService;
		readonly IReferrerService referrerService;
		readonly ISearchService searchService;
		readonly ITagService tagService;
		readonly IThemeManager themeManager;
		readonly IPageService pageService;

		public PublicControllerBase (ISearchService searchService , ICommentService commentService , IReferrerService referrerService , IConfigurationService configurationService , IWebUtils webUtils , ILogger logger , IUrlBuilder urlBuilder , IBlogRollService blogRollService , ICategoryService categoryService , IPostService postService , IThemeManager themeManager , ITagService tagService , IPageService pageService)
			: base ( configurationService , webUtils , logger , urlBuilder ) {
			this.searchService = searchService;
			this.pageService = pageService;
			this.commentService = commentService;
			this.tagService = tagService;
			this.referrerService = referrerService;
			this.blogRollService = blogRollService;
			this.categoryService = categoryService;
			this.postService = postService;
			this.themeManager = themeManager;
		}

		public IBlogRollService BlogRollService {
			get { return blogRollService; }
		}

		public ICategoryService CategoryService {
			get { return categoryService; }
		}

		public IPostService PostService {
			get { return postService; }
		}

		public IThemeManager ThemeManager {
			get { return themeManager; }
		}

		public IBlogTheme CurrentTheme {
			get { return ThemeManager.GetThemeByName ( base.Configuration.ThemeName ); }
		}

		public IReferrerService ReferrerService {
			get { return referrerService; }
		}

		public ICommentService CommentService {
			get { return commentService; }
		}

		public ITagService TagService {
			get { return tagService; }
		}

		public ISearchService SearchService {
			get { return searchService; }
		}

		public IPageService PageService {
			get { return pageService; }
		}

		protected T GetViewData <T> ( T instance ) where T : PublicBaseViewData {
			if(instance == null)
				throw new ArgumentNullException();

			instance.RecentPost = PostService.GetRecentPostDto ( 10 );
			instance.Months = PostService.GetMonths ( );
			instance.Categories = CategoryService.GetCategoriesDtoStructure ( );
			instance.BlogsRoll = BlogRollService.GetListPaged ( 0 , 30 );
			instance.RecentComment = CommentService.GetRecentCommentDto ( 10 );
			instance.TopTags = tagService.GetTopTags ( 50 );
			instance.SearchFromReferrer = PopulateReferredSearch ( );

			var pageStructures = new List <PageStructureDto> ( );
			var pages = instance.Configuration.EnabledPages;

			pageStructures.Add ( new PageStructureDto { Title = "Blog", IsPublished = true } );
			
			if (pages.EnableTagCloudRoute)
				pageStructures.Add ( new PageStructureDto { Slug = "Tag", Title = "Tag", IsPublished = true } );
			
			if (pages.EnableContactFormRoute)
				pageStructures.Add ( new PageStructureDto { Slug = "Contact", Title = "Contact", IsPublished = true } );

			pageStructures.AddRange ( PageService.GetPagesStructureRoot ().ToDtos (  ) );

			instance.Pages = pageStructures;

			return instance;
		}

		protected string[] GetKeywords ( IEnumerable<PostDto> items ) {
			if (items == null)
				return emptyStringArray;

			string[][] q = items.Select ( t => t.Tags ).ToArray ( );

			IList<String> keywords = new Collection<String> ( );

			for (int i = 0; i < q.Count ( ); i++) {
				var tags = q[i].Select ( x => x ).ToArray ( );

				foreach (var tag in tags) {
					if (!keywords.Contains ( tag )) {
						keywords.Add ( tag );
					}
				}
			}

			return keywords.ToArray ( );
		}

		protected string[] GetKeywords ( IEnumerable <Item> items ) {
			if (items == null)
				return emptyStringArray;

			IEnumerable <TagItem>[] q = items.Select ( t => t.Tags ).ToArray ( );

			IList <String> keywords = new Collection <String> ( );

			for ( int i = 0; i < q.Count ( ); i++ ) {
				var tags = q[ i ].Select ( x => x.Name ).ToArray ( );

				foreach ( var tag in tags ) {
					if ( !keywords.Contains ( tag ) ) {
						keywords.Add ( tag );
					}
				}
			}

			return keywords.ToArray ( );
		}

		protected string[] GetKeywordsFromSearchResult ( IEnumerable<SearchItem> items ) {
			if(items == null)
				return emptyStringArray;

			IEnumerable<string>[] q = items.Select ( t => t.Tags ).ToArray ( );

			IList<String> keywords = new Collection<String> ( );

			for (int i = 0; i < q.Count ( ); i++) {
				if(q[i]== null)
					continue;

				var tags = q[i].ToArray ( );

				foreach (var tag in tags) {
					if (!keywords.Contains ( tag )) {
						keywords.Add ( tag );
					}
				}
			}

			return keywords.ToArray ( );
		}

		protected override void Execute ( RequestContext requestContext ) {
			var context = requestContext.HttpContext;

			base.Execute ( requestContext );

			if ( context.Request.Url != null ) {
				if ( context.Request.UrlReferrer != null && context.Request.UrlReferrer.Host.ToLowerInvariant ( ) != context.Request.Url.Host.ToLowerInvariant ( ) ) {
					var referrer = Referrer.CreateNewReferrer ( context.Request.Url , context.Request.UrlReferrer );
					referrerService.AddReferrerAsync ( referrer );
				}
			}
		}

		SearchResult PopulateReferredSearch ( ) {
			if ( IsReferrerSearch ) {
				string referrer = HttpContext.Request.UrlReferrer.ToString ( ).ToLowerInvariant ( );
				string searchTerm = GetSearchTerm ( referrer );
				SearchResult result = this.searchService.Search ( 1 , 3 , searchTerm );
				result.SearchWords = new[] {searchTerm};

				return result;
			}

			return null;
		}

		bool IsReferrerSearch {
			get {
					return HttpContext.Request.UrlReferrer != null
						? searchPattern.IsMatch ( HttpContext.Request.UrlReferrer.ToString ( ).ToLowerInvariant ( ) )
						: false;
			}
		}

		static string GetSearchTerm ( string referrer ) {
			string term = string.Empty;
			Match match = searchPattern.Match ( referrer );

			if ( match.Success ) {
				term = match.Groups[ 1 ].Value;
			}

			term = term.Replace ( "+" , " " );
			term = term.Replace ( "-" , " " );
			term = term.Replace ( "*" , " " );

			return term;
		}

		protected void AddHeaders ( string contentType, int cacheDays, int hashCode ) {
			HttpContext.Response.ContentType = contentType;
			HttpContext.Response.ContentEncoding = Encoding.UTF8;

			HttpContext.Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
			HttpContext.Response.Cache.SetCacheability ( HttpCacheability.Public );
			HttpContext.Response.Cache.SetExpires ( DateTime.Now.AddDays ( cacheDays ) );
			HttpContext.Response.Cache.SetMaxAge ( new TimeSpan ( cacheDays, 0, 0, 0 ) );
			HttpContext.Response.Cache.SetRevalidation ( HttpCacheRevalidation.AllCaches );

			string etag = string.Concat ( "\"", hashCode, "\"" );
			string incomingEtag = HttpContext.Request.Headers["If-None-Match"];

			HttpContext.Response.Cache.SetETag ( etag );
			HttpContext.Response.Cache.SetCacheability ( HttpCacheability.Public );

			if (String.Compare ( incomingEtag, etag ) == 0) {
				HttpContext.Response.Clear ( );
				HttpContext.Response.StatusCode = ( int )HttpStatusCode.NotModified;
				HttpContext.Response.SuppressContent = true;
			}
		}
	}
}
